OpenGL:Tutorials:Tutorial Framework:Adding Depth and Color
An illusion of depth is required in our application to provide the effect of a 3D world on a 2D screen. If we just rendered our polygons to the screen, they would overlap in draw order and look pretty naff. __TOC__ Setting up the Z-Buffer The use of a Z-Buffer ensures that polygons overlap correctly. To enable the Z-Buffer within OpenGL we do two things: glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); Enabling the depth test makes every drawing operation check the Z-buffer before placing pixels onto the screen. Enabling the depth mask makes every successful drawing operation place it's depth values into the Z-buffer. Another technique that aids the illusion is backface culling. This works best with convex objects (cubes, spheres, etc). The method uses the normal vector of a polygon to determine its 'direction', only polygons that face the screen are drawn. In a cube, the three faces on the far side are not rendered, so they can't interfere with illusion of a soild object. Backface culling also reduces the on screen polycount by around a half, so it is a valuable optimisation. Enabling backface culling in OpenGL is simple: glEnable(GL_CULL_FACE); We can change the behaviour of the culling with glCullFace() if required. Depending on the order in which your vertices are specified you can pass either GL_FRONT or GL_BACK: glCullFace(GL_FRONT); // or glCullFace(GL_BACK); Adding Color In this example we're going to render a nice spinning cube, we'll color the faces to demonstrate OpenGL's color functions. glBegin(GL_QUADS); glColor3f(1.0f,0.0f,0.0f); // Red glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glColor3f(0.0f,0.0f,1.0f); // Blue glVertex3f(-1.0f,-1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glEnd(); glColor() comes in a few flavours, the one used here specifies three float values in the range 0.0 - 1.0 for red, green and blue. Other versions of the function take integer or double arguments and specify alpha values too. The color specified is used for all drawing operations after the function call. Having drawn the top and bottom faces for our cube, we now move onto the sides. // Draw the side faces glBegin(GL_TRIANGLE_STRIP); glColor3f(1.0f,1.0f,1.0f); // White glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glColor3f(0.0f,1.0f,0.0f); // Green glVertex3f( 1.0f,-1.0f, 1.0f); glColor3f(1.0f,1.0f,0.0f); // Yellow glVertex3f( 1.0f, 1.0f,-1.0f); glColor3f(0.0f,1.0f,1.0f); // Aqua? glVertex3f( 1.0f,-1.0f,-1.0f); glColor3f(0.6f,0.6f,0.6f); // Gray glVertex3f(-1.0f, 1.0f,-1.0f); glColor3f(0.1f,0.1f,0.1f); // Dark Gray glVertex3f(-1.0f,-1.0f,-1.0f); glColor3f(0.0f,0.0f,1.0f); // Blue glVertex3f(-1.0f, 1.0f, 1.0f); glColor3f(1.0f,0.0f,1.0f); // Red glVertex3f(-1.0f,-1.0f, 1.0f); glEnd(); The triangle strip drawing method treats the first three vertices as a triangle, subsequent vertices produce a new triangle using the previous two points. We specify a new color for each vertex, the result is a smooth transition between the colors rather than the flat color produced on the quads. Pressing the 'W' key during the program displays a wireframe view to illustrate how the triangle strip is created. Try commenting out the Z-Buffer and backface culling commands to see how the illusion is destroyed when the polygons are not displayed correctly. Source Code The source to Render.cpp, compile this demo using the OpenGL Tutorial Framework #include "Framework.h" void Render(void) { float Rotate=0.0f; // A rotation value to be used to spin our polygon glClearColor(0,0,0,0); // Setup our screen glViewport(0,0,800,600); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,800.0f/600.0f,1.0f,500.0f); glMatrixMode(GL_MODELVIEW); // Ensure correct display of polygons glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); // This loop will run until Esc is pressed while(RunLevel) { if(KeysVK_ESCAPE) // Esc Key RunLevel=0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and z-buffer glLoadIdentity(); // Reset current matrix (Modelview) // Press 'w' to show wireframe view if(Keys'W') glPolygonMode(GL_FRONT,GL_LINE); else glPolygonMode(GL_FRONT,GL_FILL); // Do our rotations glTranslatef(0.0f,0.0f,-5.0f); glRotatef(Rotate,0.0f,0.0f,1.0f); glRotatef(Rotate,1.0f,0.6f,0.0f); // Draw the top and bottom faces glBegin(GL_QUADS); glColor3f(1.0f,0.0f,0.0f); // Red glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glColor3f(0.0f,0.0f,1.0f); // Blue glVertex3f(-1.0f,-1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glEnd(); // Draw the side faces glBegin(GL_TRIANGLE_STRIP); glColor3f(1.0f,1.0f,1.0f); // White glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glColor3f(0.0f,1.0f,0.0f); // Green glVertex3f( 1.0f,-1.0f, 1.0f); glColor3f(1.0f,1.0f,0.0f); // Yellow glVertex3f( 1.0f, 1.0f,-1.0f); glColor3f(0.0f,1.0f,1.0f); // Aqua? glVertex3f( 1.0f,-1.0f,-1.0f); glColor3f(0.6f,0.6f,0.6f); // Gray glVertex3f(-1.0f, 1.0f,-1.0f); glColor3f(0.1f,0.1f,0.1f); // Dark Gray glVertex3f(-1.0f,-1.0f,-1.0f); glColor3f(0.0f,0.0f,1.0f); // Blue glVertex3f(-1.0f, 1.0f, 1.0f); glColor3f(1.0f,0.0f,1.0f); // Red glVertex3f(-1.0f,-1.0f, 1.0f); glEnd(); // Add to the rotation for next frame Rotate+=0.05f; // Show our cube FlipBuffers(); } }